﻿using System;
using System.Collections.Generic;
using System.Threading;
using RoMBot.MemoryLib;

namespace RoMBot.Classes
{
    public class PlayerSkill
    {
        private List<int> _effects = new List<int>();

        public PlayerSkill( int address )
        {
            //this.Address = MemoryTable.GetItemAddress( id );
            //this.Address = this.Address;
            //this.ID = id;
            this.Address = address;
            if ( this.Address != 0 )
            {
                this.Update();
            }
        }

        public void Update()
        {
            var proc = Bot.Instancia.ProcId;
            this.Id = Memory.ReadRepeat<int>( proc, this.Address );
            this.Name = MemoryTable.GetIdName( this.Id );
            this.TPToLevel = Memory.ReadRepeat<int>( proc, this.Address + Addresses.skillTPToLevel_offset );
            this.Level = Memory.ReadRepeat<int>( proc, this.Address + Addresses.skillLevel_offset );
            this.Aslevel = Memory.ReadRepeat<int>( proc, this.Address + Addresses.skillAsLevel_offset );
            this.BaseItemAddress = MemoryTable.GetItemAddress( this.Id );
            this.HotKey = Key.MACRO;

            for ( int count = 0; count < 2; count++ )
            {
                this.PowerType = ( PowerType ) Memory.ReadRepeat<int>( proc, this.BaseItemAddress + ( 8 * count ) + Addresses.skillUsesBase_offset );
                if ( this.PowerType == PowerType.None )
                    break;

                var usesnum = Memory.ReadRepeat<int>( proc, this.BaseItemAddress + ( 8 * count ) + Addresses.skillUsesBase_offset + 4 );

                switch ( this.PowerType )
                {
                    case PowerType.Mana:
                        if ( this.Level > 49 )
                        {
                            this.Mana = ( int ) ( usesnum * ( 5.8 + ( this.Level - 49 ) * 0.2 ) );
                        }
                        else if ( this.Level > 1 )
                        {
                            this.Mana = ( int ) ( usesnum * ( 1 + ( this.Level - 1 ) * 0.1 ) );
                        }
                        else
                        {
                            this.Mana = usesnum;
                        }
                        break;
                    case PowerType.Rage:
                        this.Rage = usesnum;
                        break;
                    case PowerType.Focus:
                        this.Focus = usesnum;
                        break;
                    case PowerType.Energy:
                        this.Energy = usesnum;
                        break;
                    case PowerType.MpPercent:
                        break;
                    case PowerType.Item:
                        this.Consumable = "item";
                        this.ConsumableNumber = usesnum;
                        break;
                    case PowerType.Proyectile:
                        this.Consumable = "proyectile";
                        this.ConsumableNumber = usesnum;
                        break;
                    case PowerType.Arrow:
                        this.Consumable = "arrow";
                        this.ConsumableNumber = usesnum;
                        break;
                    case PowerType.Psi:
                        this.Psi = usesnum;
                        break;
                }
                //if (uses == SKILLUSES_MANA) then
                //    if tmp.Level > 49 then
                //        tmp.Mana = usesnum * (5.8 + (tmp.Level - 49)*0.2)
                //    elseif tmp.Level > 1 then
                //        tmp.Mana = usesnum * (1 + (tmp.Level - 1)*0.1)
                //    else
                //        tmp.Mana = usesnum
                //    end
                //elseif uses == SKILLUSES_RAGE then
                //    tmp.Rage = usesnum
                //elseif uses == SKILLUSES_FOCUS then
                //    tmp.Focus = usesnum
                //elseif uses == SKILLUSES_ENERGY then
                //    tmp.Energy = usesnum
                //elseif uses == SKILLUSES_ITEM then
                //    tmp.Consumable = "item"
                //    tmp.ConsumableNumber = usesnum
                //elseif uses == SKILLUSES_PROJECTILE then
                //    tmp.Consumable = "projectile"
                //    tmp.ConsumableNumber = usesnum
                //elseif uses == SKILLUSES_ARROW then
                //    tmp.Consumable = "arrow"
                //    tmp.ConsumableNumber = usesnum
                //elseif uses == SKILLUSES_PSI then
                //    tmp.Psi = usesnum
                //elseif uses ~= 3 and uses ~= 4 then -- known unused 'uses' values.
                //    printf("Skill %s 'uses' unknown type %d, 'usesnum' %d. Please report to bot devs. We might be able to use it.\n",tmp.Name, uses, usesnum)
                //end

            }

            //var nameAddress = Memory.ReadInt( this.Address + Addresses.nameOffset );
            //// Por ahora ignoramos los skills sin nombre que son efectos y no nos interesan para esto...
            //if ( nameAddress != 0 && nameAddress != Helpers.EMPTY_NAME_MARKER )
            //{
            //    _effects.Clear();

            //    this.Name = Memory.ReadUtf8String( nameAddress );

            //    var effect = Memory.ReadInt( this.Address + Addresses.Instance[ "skillEffect1_offset" ] );
            //    if ( effect >= 500000 )
            //        _effects.Add( effect );
            //    effect = Memory.ReadInt( this.Address + Addresses.Instance[ "skillEffect2_offset" ] );
            //    if ( effect >= 500000 )
            //        _effects.Add( effect );
            //    effect = Memory.ReadInt( this.Address + Addresses.Instance[ "skillEffect3_offset" ] );
            //    if ( effect >= 500000 )
            //        _effects.Add( effect );
            //    effect = Memory.ReadInt( this.Address + Addresses.Instance[ "skillEffect4_offset" ] );
            //    if ( effect >= 500000 )
            //        _effects.Add( effect );

            //    this.Level = Bot.Player.Level; // Asumimos que el skill es del level del player, esto es mejor que asumir que son todos lvl 0 y tratar de castear un skill cuando no nos alcanza el maná...
            //    this.Cooldown = Memory.ReadInt( this.Address + Addresses.skillCooldown_offset );
            //    this.Range = Memory.ReadInt( this.Address + Addresses.skillRange_offset );
            //    this.RangeAoE = Memory.ReadInt( this.Address + Addresses.skillRangeAoE_offset );
            //    this.PowerType = ( PowerType ) Memory.ReadInt( this.Address + Addresses.skillEnergyTypeUsed_offset );
            //    this.CastTime = Memory.ReadFloat( this.Address + Addresses.skillCastTime_offset );

            //    if ( ( int ) this.PowerType > 0 )
            //    {
            //        var power = Memory.ReadInt( this.Address + Addresses.skillEnergy_offset );
            //        if ( power > 0 && ( int ) this.PowerType > 0 && ( int ) this.PowerType < 9 )
            //        {
            //            if ( this.PowerType == RoMBotDll.PowerType.Percent ) // Porcentaje
            //            {
            //                this.Power = ( int ) ( ( ( float ) Bot.Player.MaxPower1 / 100f ) * ( float ) power );
            //            }
            //            else if ( this.PowerType == PowerType.Mana )
            //            {
            //                this.Power = ( ( power / 10 ) * ( this.Level > 1 ? this.Level - 1 : 0 ) ) + ( int ) ( power * 1.5 );
            //            }
            //            else
            //            {
            //                this.Power = power;
            //            }
            //        }
            //        else
            //        {
            //            this.Power = 0;
            //        }

            //        if ( this.PowerType == RoMBotDll.PowerType.Object )
            //        {
            //            this.IdObjectConsumed = Memory.ReadInt( this.Address + Addresses.skillEnergy_offset );
            //        }
            //    }

            //    this.Passive = Memory.ReadInt( this.Address + Addresses.skillPassiveFlag_offset ) == 2;

            //    if ( !this.Passive )
            //    {
            //        var requiereExista = Memory.ReadInt( this.Address + Addresses.skillRequiredEffectFlag_offset );
            //        this.RequiresEffectToExist = requiereExista == 4;
            //        this.RequiredEffect = Memory.ReadInt( this.Address + Addresses.skillRequiredEffect_offset );

            //        var attackFlag = Memory.ReadInt( this.Address + Addresses.skillAttackFlag_offset );
            //        var attack = attackFlag == 1 || attackFlag == 4;
            //        var buff = Memory.ReadInt( this.Address + Addresses.skillBuffFlag_offset ) == 1;
            //        var selfBuff = Memory.ReadInt( this.Address + Addresses.skillSelfBuffFlag_offset ) == 1;
            //        var aoe = Memory.ReadInt( this.Address + Addresses.skillAoEFlag_offset );
            //        var targetType = Memory.ReadInt( this.Address + Addresses.skillTargetType_offset );
            //        var typeFlag1 = Memory.ReadByte( this.Address + Addresses.Instance[ "skillTypeFlag1_offset" ] );
            //        var typeFlag2 = Memory.ReadByte( this.Address + Addresses.Instance[ "skillTypeFlag2_offset" ] );
            //        var typeFlag3 = Memory.ReadByte( this.Address + Addresses.Instance[ "skillTypeFlag3_offset" ] );
            //        var typeFlag4 = Memory.ReadByte( this.Address + Addresses.Instance[ "skillTypeFlag4_offset" ] );
            //        var typeFlag5 = Memory.ReadByte( this.Address + Addresses.Instance[ "skillTypeFlag5_offset" ] );
            //        var typeFlag6 = Memory.ReadByte( this.Address + Addresses.Instance[ "skillTypeFlag6_offset" ] );
            //        var typeFlag7 = Memory.ReadByte( this.Address + Addresses.Instance[ "skillTypeFlag7_offset" ] );
            //        var typeFlag8 = Memory.ReadByte( this.Address + Addresses.Instance[ "skillTypeFlag8_offset" ] );
            //        var typeFlag9 = Memory.ReadByte( this.Address + Addresses.Instance[ "skillTypeFlag9_offset" ] );

            //        if ( ( buff || selfBuff ) && !attack )
            //        {
            //            // No estoy muy seguro si esta bien pero de esta manera me aseguro de seleccionar el player antes de bufear...
            //            this.TargetType = SkillTargetType.Self;
            //            this.Buff = buff && !selfBuff;
            //            this.SelfBuff = selfBuff && !attack;
            //            this.AoE = aoe == 2;
            //            if ( this.AoE )
            //            {
            //                this.TargetType = SkillTargetType.None;
            //                this.Buff = true;
            //                this.SelfBuff = false;
            //            }
            //        }
            //        //else
            //        {
            //            switch ( targetType )
            //            {
            //                case 2:
            //                    this.TargetType = SkillTargetType.Pet;
            //                    break;
            //                case 4:
            //                    this.TargetType = SkillTargetType.Friendly;
            //                    break;
            //                case 6:
            //                    this.TargetType = SkillTargetType.Enemy;
            //                    break;
            //                default:
            //                    this.TargetType = SkillTargetType.None;
            //                    break;
            //            }
            //        }

            //        //if ( !attack && !selfBuff )
            //        //{
            //        //var effectAddress = GameTables.GetItemAddress( this.EffectId1 );
            //        //this.EffectAddress = effectAddress;
            //        //if ( this.EffectId2 != 0 )
            //        //{
            //        //    effectAddress = GameTables.GetItemAddress( this.EffectId2 );
            //        //    this.EffectAddress2 = effectAddress;
            //        //}
            //        //}
            //        /*else */
            //        if ( attack )
            //        {
            //            this.Buff = false; //Esto probablemente tenga más significados que simplemente "buff" pero por ahora sirve asi...
            //            this.SelfBuff = false;

            //            this.Attack = true;
            //            this.AoE = aoe == 3;
            //            this.Debuff = buff;

            //            if ( this.AoE )
            //            {
            //                this.TargetType = SkillTargetType.None;
            //            }

            //            if ( this.Debuff && !this.AoE )
            //            {
            //                this.TargetType = SkillTargetType.Enemy;
            //            }

            //            //if ( this.Debuff || ( !this.Debuff && ( typeFlag4 == 0x00 && typeFlag5 == 0x00 && typeFlag7 == 0x01 && typeFlag9 == 0x00 ) ) )
            //            //{
            //            //    this.DoT = true;
            //            //}
            //        }

            //        if ( !this.Attack )
            //        {
            //            if ( !this.SelfBuff && typeFlag8 == 0 && ( ( typeFlag1 == 0x01 && typeFlag2 == 0x00 && typeFlag3 == 0x40 ) || ( typeFlag1 == 0x00 && ( typeFlag2 == 0x00 && typeFlag3 == 0x40 && typeFlag4 == 0x00 ) ) ) )
            //            {
            //                this.Heal = true;

            //                if ( this.Buff || ( !this.Buff && ( typeFlag4 == 0x00 && typeFlag5 == 0x00 && typeFlag7 == 0x01 && typeFlag9 == 0x00 ) ) )
            //                {
            //                    this.HoT = true;
            //                }
            //            }
            //        }

            //        if ( typeFlag1 == 0x03 && typeFlag2 == 0x41 )
            //        {
            //            this.Summon = true;
            //        }

            //        if ( ( typeFlag5 > 0 && typeFlag5 < 10 ) && ( ( typeFlag1 == 0x10 && typeFlag2 == 0x00 ) || ( typeFlag1 == 0x11 && typeFlag2 == 0x40 ) ) )
            //        {
            //            if ( typeFlag3 == 0x40 && typeFlag4 == 0 )
            //            {
            //                this.PetSkill = true;
            //            }
            //        }

            //        // Busquemos algunos detalles más...
            //        //if ( ( this.Heal || this.Buff || this.Debuff ) && this.EffectAddress != 0 )
            //        //{
            //        //    var heal = Memory.ReadInt( this.EffectAddress + Addresses.effectType_offset ) == 4;
            //        //    var isMain = Memory.ReadInt( this.EffectAddress + Addresses.effectIsMainFlag_offset ) == 1;
            //        //    //if ( heal && !this.Attack && !this.Debuff )
            //        //    //{
            //        //    //    this.Heal = true;
            //        //    //}
            //        //    if ( isMain )
            //        //    {
            //        //        this.Duration = Memory.ReadFloat( this.EffectAddress + Addresses.effectDuration_offset );
            //        //    }
            //        //    else if ( this.EffectAddress2 != 0 )
            //        //    {
            //        //        this.Duration = Memory.ReadFloat( this.EffectAddress2 + Addresses.effectDuration_offset );
            //        //    }

            //        //    if ( this.Heal && this.Duration > 0 )
            //        //    {
            //        //        this.HoT = true;
            //        //    }
            //        //}
            //        //else if ( this.EffectAddress == 0 && this.Debuff && this.EffectAddress2 != 0 )
            //        //{
            //        //    this.Duration = Memory.ReadFloat( this.EffectAddress2 + Addresses.effectDuration_offset );
            //        //}
            //    }
            //    else
            //    {
            //        this.TargetType = SkillTargetType.None;
            //    }

            //    this.Updated = true;
            //}
        }

        public bool CanUse( bool _only_friendly = false, Pawn target = null )
        {
            if ( this.HotKey == Key.VK_NONE )
                return false;

            if ( target != null )
            {
                this.Target = target;
            }

            if ( this.Target == null )
            {
                Bot.Player.Update();
                this.Target = Bot.Player.Target;
            }

            if ( this.Target == null && this.TargetType != SkillTargetType.Self && this.TargetType != SkillTargetType.None )
            {
                return false;
            }

            // only friendly skill types?
            if ( _only_friendly )
            {
                if ( !this.Heal &&
                     !this.HoT &&
                     !this.Summon &&
                     !this.Buff &&
                     !this.SelfBuff )
                {
                    Logger.Warning( "Only friendly selected and this skill is not that type: " + this.Name );
                    return false;
                }
            }

            // Still cooling down...
            if ( ( DateTime.Now - this.LastCastTime ).TotalMilliseconds < ( this.Cooldown * 1000 - this.RebuffCut * 1000 - Bot.Player.Profile.GetOptionValue<int>( "SKILL_USE_PRIOR" ) ) ) // Cooldown is in sec
            {
                Logger.Warning( "Skill is on cooldown: " + this.Name );
                return false;
            }

            // You don't meet the maximum HP percent requirement
            if ( Bot.Player.MaxHP == 0 ) { Bot.Player.MaxHP = 1; } // prevent division by zero
            //if ( ( this.MaxHpPer < 0 ? -1 : 1 ) * ( Bot.Player.HP / Bot.Player.MaxHP * 100 ) > this.MaxHpPer )
            //{
            //    Logger.Warning( string.ItemLinkFormat( "Player has: {0}% HP, skill requires: {1}% HP to be casted.", Bot.Player.HP / Bot.Player.MaxHP * 100, this.MaxHpPer ) );
            //    return false;
            //}

            //if ( ( this.MaxManaPer < 0 ? -1 : 1 ) * ( Bot.Player.Mana / Bot.Player.MaxMana * 100 ) > this.MaxManaPer )
            //{
            //    //debug_skilluse("MAXMANAPER", (Bot.Player.Mana/Bot.Player.MaxMana*100), this.MaxManaPer);
            //    return false;
            //}

            // You are ! above the minimum Mana Percent
            //if ( ( Bot.Player.Mana / Bot.Player.MaxMana * 100 ) < this.MinManaPer )
            //{
            //    //debug_skilluse("MINMANAPER", (Bot.Player.Mana/Bot.Player.MaxMana*100), this.MinManaPer);
            //    return false;
            //}

            switch ( this.PowerType )
            {
                case PowerType.Mana:
                case PowerType.MpPercent:
                    if ( Bot.Player.MP < this.Power ) { return false; }
                    break;
                case PowerType.Focus:
                    if ( Bot.Player.Focus < this.Power ) { return false; }
                    break;
                case PowerType.Energy:
                    if ( Bot.Player.Energy < this.Power ) { return false; }
                    break;
                case PowerType.Item:
                    if ( Bot.Player.Inventory.GetItemCount( this.IdObjectConsumed ) < this.Power ) { return false; }
                    break;
                case PowerType.Proyectile:
                    //if ( Bot.Player.Focus < this.Energy ) { return false; }
                    break;
                case PowerType.Arrow:
                    break;
            }

            // This skill cannot be used in battle
            if ( Bot.Player.Battling && this.InBattle == false )
            {
                Logger.Warning( "This skill cannot be casted in battle: " + this.Name );
                return false;
            }

            // check if hp below our HP_LOW level
            if ( this.Heal || this.HoT )
            {
                var hpper = ( Bot.Player.HP / Bot.Player.MaxHP * 100 );

                if ( this.MaxHpPer != 100 )
                {
                    if ( hpper > this.MaxHpPer )
                    {
                        return false;
                    }
                }
                else
                {
                    // Inherit from settings' HP_LOW
                    if ( hpper > Bot.Player.Profile.GetOptionValue<int>( "HP_LOW" ) )
                    {
                        //debug_skilluse("HPLOW", hpper, "greater as setting", settings.profile.options.HP_LOW );
                        return false;
                    }
                }
            }


            // skill with maximum use per fight
            if ( this.MaxUse > 0 && this.Used >= this.MaxUse )
            {
                //debug_skilluse("MAXUSE", this.used, this.maxuse);
                return false;
            }

            // Needs an enemy target
            if ( this.TargetType == SkillTargetType.Enemy && this.Target == null )
            {
                return false;
            }

            // DOTs require the enemy to have > X% hp
            //if ( this.Type == SkillType.DoT )
            //{
            //    var hpper = ( target.HP / target.MaxHP ) * 100;
            //    if ( hpper < Bot.Player.Profile.GetOptionValue<int>( "DOT_PERCENT" ) )
            //    {
            //        //debug_skilluse("DOTHPPER", hpper, settings.profile.options.DOT_PERCENT);
            //        return false;
            //    }
            //}

            // only if target HP % is below given level
            //if ( target != null && ( ( this.TargetMaxHpPer < 0 ? -1 : 1 ) * ( target.HP / target.MaxHP * 100 ) ) > this.TargetMaxHpPer )
            //{
            //    //debug_skilluse("TARGETHPPER", target.HP/target.MaxHP*100 );
            //    return false;
            //}

            //// only if target HP points is below given level
            //if ( target != null && ( ( this.TargetMaxHp < 0 ? -1 : 1 ) * target.HP ) > this.TargetMaxHp )
            //{
            //    //debug_skilluse("TARGEHP", target.HP );
            //    return false;
            //}

            // Out of range
            if ( Bot.Player.DistanceToTarget > this.Range &&
                this.TargetType != SkillTargetType.Self &&
                this.TargetType != SkillTargetType.None )
            {		// range check only if no selftarget skill
                //debug_skilluse("OUTOFRANGE", Bot.Player:distanceToTarget(), this.Range );
                return false;
            }

            // Too close
            if ( Bot.Player.DistanceToTarget < this.MinRange &&
                this.TargetType != SkillTargetType.Self &&
                this.TargetType != SkillTargetType.None )
            {		// range check only if no selftarget skill
                //debug_skilluse("MINRANGE", Bot.Player:distanceToTarget(), this.MinRange );
                return false;
            }

            // check pullonly skills
            if ( this.PullOnly &&
                !Bot.Player.RangedPull )
            {
                //debug_skilluse("PULLONLY");
                return false;
            }

            // Not enough mana
            if ( Bot.Player.Mana < this.Power )
            {
                //debug_skilluse("NOTENOUGHMANA", Bot.Player.Mana, math.ceil(this.Mana + (this.Level-1)*this.ManaInc));
                return false;
            }

            // Already have a pet out
            if ( this.Summon && Bot.Player.PetPtr != 0 )
            {
                //debug_skilluse("PETALREAYDOUT");
                return false;
            }

            if ( this.Toggleable && this.Toggled == true )
            {
                //debug_skilluse("TOGGLED");
                return false;
            }

            return true;
        }

        public bool Use()
        {
            if ( !this.CanUse() )
            {
                return false;
            }
            //Bot.Player.Profile.OnBeforeSkillCast( this );

            var estimatedMana = 0m;
            if ( this.MinManaPer > 0 )
            {
                estimatedMana = Math.Ceiling( ( decimal ) ( ( this.MinManaPer / 100 ) * Bot.Player.MaxMana ) );
            }
            else
            {
                estimatedMana = this.Power;
            }

            var target = Bot.Player.Target;

            if ( this.HotKey == Key.VK_NONE )
            {
                var str = string.Format( "Bad skill hotkey name: {0}.\n", this.Name );
                Logger.Log( str, LogType.Error );
                return false;
            }

            this.Used++;	// count use of skill per fight

            this.LastCastTime = DateTime.Now;
            this.LastCastTime += TimeSpan.FromMilliseconds( 1 * 1000 * 3345 );
            if ( this.CastTime > 0 )
            {
                Bot.Player.LastSkillCastTime = this.CastTime;
                //TODO: Ver que hacer con esto
                //Bot.Player.LastSkillType = this.s;
            }

            while ( ( DateTime.Now - Bot.Instancia.LastSkillKeypressTime ).TotalMilliseconds < Bot.Player.Profile.GetOptionValue<int>( "SKILL_GLOBALCOOLDOWN" ) - Bot.Player.Profile.GetOptionValue<int>( "SKILL_USE_PRIOR" ) )
            {
                Thread.CurrentThread.Join( 10 );
            }

            Bot.Instancia.LastSkillKeypressTime = DateTime.Now;		// remember time to check time-lag between casts

            if ( this.HotKey == Key.MACRO )
            {
                Helpers.RoMScript( "CastSpellByName('" + this.Name + "');" );
            }
            else
            {
                // use the normal hotkeys
                Keyboard.KeyPress( this.HotKey, this.Modifier );
            }

            if ( this.Toggleable )
            {
                this.Toggled = true;
            }

            //Bot.Player.Profile.OnSkillCast( this );
            return true;
        }

        public int Address { get; set; }

        public int ID { get; set; }

        public string Name { get; set; }

        public int Power { get; set; }

        public int Level { get; set; }

        public int Range { get; set; }

        public int Cooldown { get; set; }

        public DateTime LastCastTime { get; set; }

        public PowerType PowerType { get; set; }

        public int RangeAoE { get; set; }

        public bool Passive { get; set; }

        public SkillTargetType TargetType { get; set; }

        public bool Attack { get; set; }

        public bool AoE { get; set; }

        public bool Buff { get; set; }

        public bool SelfBuff { get; set; }

        public bool Debuff { get; set; }

        public bool Heal { get; set; }

        public bool HoT { get; set; }

        public float Duration { get; set; }

        internal bool Updated { get; set; }

        public bool Summon { get; set; }

        public bool PetSkill { get; set; }

        public Key HotKey { get; set; }

        public Key Modifier { get; set; }

        public bool AutoUse { get; set; }

        public bool PullOnly { get; set; }

        public int MaxUse { get; set; }

        public float RebuffCut { get; set; }

        public int Used { get; set; }

        public int MinManaPer { get; set; }

        public int MaxManaPer { get; set; }

        public int TargetMinManaPer { get; set; }

        public int TargetMaxManaPer { get; set; }

        public int MinHpPer { get; set; }

        public int MaxHpPer { get; set; }

        public int TargetMinHpPer { get; set; }

        public int TargetMaxHpPer { get; set; }

        public int MinMana { get; set; }

        public int MaxMana { get; set; }

        public int TargetMinMana { get; set; }

        public int TargetMaxMana { get; set; }

        public int MinHp { get; set; }

        public int MaxHp { get; set; }

        public int TargetMinHp { get; set; }

        public int TargetMaxHp { get; set; }

        public GameObject Target { get; set; }

        public bool Toggleable { get; set; }

        public bool Toggled { get; set; }

        public bool InBattle { get; set; }

        public int MinRange { get; set; }

        public float CastTime { get; set; }

        public int IdObjectConsumed { get; set; }

        public bool DoT { get; set; }

        public List<int> Effects
        {
            get { return this._effects; }
            set { this._effects = value; }
        }

        public int RequiredEffect { get; set; }

        public bool RequiresEffectToExist { get; set; }

        public int Id { get; set; }

        public int TPToLevel { get; set; }

        public int Aslevel { get; set; }

        public int BaseItemAddress { get; set; }

        public int Mana { get; set; }

        public int Rage { get; set; }

        public int Focus { get; set; }

        public int Energy { get; set; }

        public string Consumable { get; set; }

        public int ConsumableNumber { get; set; }

        public int Psi { get; set; }

        public int SkillNum { get; set; }

        public int SkillTab { get; set; }
    }
}